package com.luter.heimdall.starter.jfinal.interceptor;

import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.render.HtmlRender;
import com.luter.heimdall.core.config.ConfigManager;
import com.luter.heimdall.core.config.HeimdallProperties;
import com.luter.heimdall.core.exception.HeimdallUnauthenticatedException;
import com.luter.heimdall.core.exception.HeimdallUnauthorizedException;
import com.luter.heimdall.core.fuction.AbVoidFunction;
import com.luter.heimdall.core.manager.AuthorizationManager;
import com.luter.heimdall.core.token.SimpleToken;
import com.luter.heimdall.core.utils.PathUtil;
import org.slf4j.Logger;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

import static org.slf4j.LoggerFactory.getLogger;

/**
 * The type Auth way j final authorize interceptor.
 *
 * @author luter
 */
public class HeimdallJFinalAuthorizeInterceptor implements Interceptor {
    /**
     * The constant log.
     */
    private static final transient Logger log = getLogger(HeimdallJFinalAuthorizeInterceptor.class);
    /**
     * The constant PATH_UTIL.
     */
    private static final PathUtil PATH_UTIL = new PathUtil();
    /**
     * The Authorization manager.
     */
    private final AuthorizationManager authorizationManager;

    /**
     * The Success.
     */
    private AbVoidFunction<Invocation, SimpleToken> success;
    /**
     * The Error.
     */
    private AbVoidFunction<Invocation, Throwable> error;

    /**
     * Instantiates a new Auth way j final authorize interceptor.
     *
     * @param authorizationManager the authorization manager
     */
    public HeimdallJFinalAuthorizeInterceptor(AuthorizationManager authorizationManager) {
        this.authorizationManager = authorizationManager;
    }

    @Override
    public void intercept(Invocation invocation) {
        final HttpServletRequest request = invocation.getController().getRequest();
        final String method = request.getMethod();
        final String uri = request.getRequestURI();
        final HeimdallProperties config = ConfigManager.getConfig();
        final boolean enabled = config.getAuthority().isEnabled();
        final List<String> includePatterns = config.getAuthority().getIncludes();
        final List<String> excludePatterns = config.getAuthority().getExcludes();
        try {
            if (enabled && PATH_UTIL.isMatch(includePatterns, uri)
                    && !PATH_UTIL.isMatch(excludePatterns, uri)) {
                //是否登录
                final SimpleToken currentToken = authorizationManager.getAuthenticationManager()
                        .getCurrentToken(true);
                //是否授权
                authorizationManager.isAuthorized(currentToken.getDetails(), method, uri, true);
                if (null != success) {
                    success.accept(invocation, currentToken);
                }
            }
            invocation.invoke();
        } catch (Throwable throwable) {
            if (null != error) {
                error.accept(invocation, throwable);
            } else {
                throwable.printStackTrace();
                log.error(throwable.getMessage());
                Controller c = invocation.getController();
                int status = 500;
                if (throwable instanceof HeimdallUnauthenticatedException) {
                    status = 401;
                }
                if (throwable instanceof HeimdallUnauthorizedException) {
                    status = 403;
                }
                c.renderError(status, new HtmlRender(throwable.getMessage()));
            }

        }

    }

    /**
     * On success auth way j final authorize interceptor.
     *
     * @param success the success
     * @return the auth way j final authorize interceptor
     */
    public HeimdallJFinalAuthorizeInterceptor onSuccess(AbVoidFunction<Invocation, SimpleToken> success) {
        this.success = success;
        return this;
    }

    /**
     * On error auth way j final authorize interceptor.
     *
     * @param error the error
     * @return the auth way j final authorize interceptor
     */
    public HeimdallJFinalAuthorizeInterceptor onError(AbVoidFunction<Invocation, Throwable> error) {
        this.error = error;
        return this;
    }
}
